/**
* Copyright 2014 Confluent Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.confluent.rest;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.jetty.JettyTestContainerFactory;
import org.junit.After;
import org.junit.Before;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.core.Application;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.Vector;
public abstract class
EmbeddedServerTestHarness<C extends RestConfig, T extends io.confluent.rest.Application<C>> {
private List<Object> resources = new Vector<Object>();
private List<Class<?>> resourceClasses = new Vector<Class<?>>();
protected C config;
protected T app;
private JerseyTest test;
public EmbeddedServerTestHarness() throws RestConfigException {
this.config = createConfiguration();
}
public EmbeddedServerTestHarness(C config) {
this.config = config;
}
private C createConfiguration() throws RestConfigException {
Class<C> configClass = Generics.getTypeParameter(getClass(), RestConfig.class);
try {
return configClass.getConstructor().newInstance();
} catch (NoSuchMethodException e) {
throw new RestConfigException(
"Couldn't find default constructor for " + configClass.getName(), e
);
} catch (IllegalAccessException e) {
throw new RestConfigException(
"Error invoking default constructor " + configClass.getName(), e
);
} catch (InvocationTargetException e) {
throw new RestConfigException(
"Error invoking default constructor for " + configClass.getName(), e
);
} catch (InstantiationException e) {
throw new RestConfigException(
"Error invoking default constructor for " + configClass.getName(), e
);
}
}
/**
* Creates and configures an application. This may be overridden by subclasses if they need
* to customize the Application's Configuration or invoke a constructor other than
* Application(Configuration c).
*/
protected T createApplication() throws RestConfigException {
Class<T> appClass = Generics.getTypeParameter(getClass(), io.confluent.rest.Application.class);
try {
return appClass.getConstructor(this.config.getClass()).newInstance(this.config);
} catch (NoSuchMethodException e) {
throw new RestConfigException(
"Couldn't find default constructor for " + appClass.getName(), e
);
} catch (IllegalAccessException e) {
throw new RestConfigException(
"Error invoking default constructor " + appClass.getName(), e
);
} catch (InvocationTargetException e) {
throw new RestConfigException(
"Error invoking default constructor for " + appClass.getName(), e
);
} catch (InstantiationException e) {
throw new RestConfigException(
"Error invoking default constructor for " + appClass.getName(), e
);
}
}
@Before
public void setUp() throws Exception {
try {
app = createApplication();
} catch (RestConfigException ce) {
throw new RuntimeException(
"Unexpected configuration error when configuring EmbeddedServerTestHarnesss.", ce
);
}
getJerseyTest().setUp();
}
@After
public void tearDown() throws Exception {
test.tearDown();
test = null;
}
protected void addResource(Object resource) {
resources.add(resource);
}
protected void addResource(Class<?> resource) {
resourceClasses.add(resource);
}
protected T getApp() {
return app;
}
protected JerseyTest getJerseyTest() {
// This is instantiated on demand since we need subclasses to register the resources they need
// passed along, but JerseyTest calls configure() from its constructor.
if (test == null) {
test = new JettyJerseyTest();
}
return test;
}
protected Invocation.Builder request(String target, String mediatype) {
Invocation.Builder builder = getJerseyTest().target(target).request();
if (mediatype != null) {
builder.accept(mediatype);
}
return builder;
}
private class JettyJerseyTest extends JerseyTest {
public JettyJerseyTest() {
super(new JettyTestContainerFactory());
}
@Override
protected Application configure() {
ResourceConfig config = new ResourceConfig();
// Only configure the base application, resources are added manually with addResource
app.configureBaseApplication(config, null);
for (Object resource : resources) {
config.register(resource);
}
for (Class<?> resource : resourceClasses) {
config.register(resource);
}
return config;
}
@Override
protected void configureClient(ClientConfig config) {
app.configureBaseApplication(config, null);
}
}
}